package dtm

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	// "fmt"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/moneyx"
	"mall/common/mqueuex"
	"mall/common/resultx"
	"mall/service/backend/common/i18n"
	"mall/service/user/model"
	"mall/service/user/rpc/internal/svc"
	"mall/service/user/rpc/types/user"

	"github.com/dtm-labs/client/dtmcli"
	"github.com/dtm-labs/client/dtmgrpc"

	// "github.com/sirupsen/logrus"
	"github.com/volatiletech/sqlboiler/v4/boil"
	"github.com/volatiletech/sqlboiler/v4/queries/qm"
	"github.com/zeromicro/go-zero/core/logx"
	"google.golang.org/grpc/codes"
)

type UpdateUserAssetRawLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewUpdateUserAssetRawLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateUserAssetRawLogic {
	return &UpdateUserAssetRawLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *UpdateUserAssetRawLogic) UpdateUserAssetRaw(in *user.UpdateUserAssetReq) (*user.BaseResp, error) {
	// logrus.Info(fmt.Sprintf("UpdateUserAssetRaw UpdateUserAssetReq: %+v", in))
	logx.Infof("UpdateUserAssetRaw : %+v ", in)
	// UserId:10021  AssetType:3  ChangeType:2  ChangeAmount:\"10000000\"  SourceType:8  SourceId:6  SourceDesc:\"兑换优惠券\" ","level":"info"}
	fmt.Println(in, "in  UpdateUserAssetRaw")
	if in.UserId == nil || *in.UserId == 0 {
		return nil, resultx.StatusError(resultx.USER_ID_REQUIRED, "")
	}
	fmt.Println(in, "in")
	fmt.Println(in.UserId, "in")
	fmt.Println(in.AssetType, "in")
	fmt.Println(in.ChangeAmount, "in")
	if in.AssetType == nil || *in.AssetType == 0 {
		return nil, resultx.StatusError(resultx.USER_ASSET_INVALID, "")
	}

	assetType := *in.AssetType

	if in.ChangeAmount == nil || len(strings.TrimSpace(*in.ChangeAmount)) == 0 {
		return nil, resultx.StatusError(resultx.USER_ASSET_INVALID, "")
	}

	var changeAmount int64
	if assetType == globalkey.UserAssetTypeGem { // 宝石
		if val, err := moneyx.ParseGem(strings.TrimSpace(*in.ChangeAmount)); err != nil || val == 0 {
			return nil, resultx.StatusError(resultx.USER_ASSET_INVALID, "")
		} else {
			changeAmount = val
		}
	} else if assetType == globalkey.UserAssetTypePoint { // 积分
		if val, err := strconv.ParseInt(strings.TrimSpace(*in.ChangeAmount), 10, 64); err != nil || val == 0 {
			return nil, resultx.StatusError(resultx.USER_ASSET_INVALID, "")
		} else {
			changeAmount = val
		}
	}

	// 获取子事务屏障对象
	barrier, err := dtmgrpc.BarrierFromGrpc(l.ctx)
	if err != nil {
		return nil, resultx.StatusError(resultx.DTM_ERROR, err.Error())
	}

	// 开启子事务屏障
	err = barrier.CallWithDB(l.svcCtx.DB, func(tx *sql.Tx) error {
		var mods []qm.QueryMod
		mods = append(mods, model.UserAccountWhere.UserID.EQ(*in.UserId))
		mods = append(mods, qm.Limit(1))
		list, err := model.UserAccounts(mods...).All(l.ctx, tx)
		if err != nil {
			if err == sql.ErrNoRows {
				return resultx.StatusError(resultx.USER_ID_INVALID, "")
			}

			return err
		}

		if len(list) == 0 {
			return resultx.StatusError(resultx.USER_ID_INVALID, "")
		}

		account := list[0]
		var changeType int64 = 1
		if in.ChangeType != nil && *in.ChangeType == globalkey.UserAssetChangeTypeDecrease {
			changeType = -1
		}

		var field string
		if assetType == globalkey.UserAssetTypeGem { // 宝石
			account.Balance = account.Balance + changeType*changeAmount
			if account.Balance < 0 {
				return dtmcli.ErrFailure
			}

			field = model.UserAccountColumns.Balance
		} else if assetType == globalkey.UserAssetTypePoint { // 积分
			account.Point = account.Point + changeType*changeAmount
			if account.Point < 0 {
				return dtmcli.ErrFailure
			}

			field = model.UserAccountColumns.Point
		}

		rowsAff, err := account.Update(l.ctx, tx, boil.Whitelist(field))
		if err != nil {
			return err
		}

		if rowsAff == 0 {
			return dtmcli.ErrFailure
		}

		now := time.Now()
		log := &model.UserTransactionLog{
			UserID:       *in.UserId,
			AssetType:    uint8(assetType),
			ChangeAmount: strings.TrimSpace(*in.ChangeAmount),
			Status:       uint8(globalkey.StatusEnabled),
			CreatedAt:    now,
			UpdatedAt:    now,
		}
		if in.ChangeType != nil {
			log.ChangeType = uint8(*in.ChangeType)
		}
		skipTaskLog := true
		updateUserMeta := false
		skipIntegralLog := true
		if in.SourceType != nil {
			log.SourceType = uint8(*in.SourceType)
			if *in.SourceType == globalkey.UserAssetSourceTypeTask {
				skipTaskLog = false
			} else if *in.SourceType == globalkey.UserAssetSourceTypeCoupon {
				updateUserMeta = true
			} else if *in.SourceType == globalkey.UserAssetSourceTypeProduct && in.SourceDesc != nil && len(*in.SourceDesc) > 0 {
				skipIntegralLog = false
			}
		}
		if in.SourceId != nil {
			log.SourceID = *in.SourceId
		}
		if in.SourceDesc != nil {
			log.Desc = *in.SourceDesc
		}

		err = log.Insert(l.ctx, tx, boil.Infer())
		if err != nil {
			return resultx.StatusError(resultx.DB_ERROR, "")
		}

		//积分任务，添加日志
		if !skipTaskLog {
			taskLog := &model.UserTaskLog{
				UserID:    *in.UserId,
				Status:    uint8(globalkey.StatusEnabled),
				CreatedAt: now,
				UpdatedAt: now,
			}
			if in.TaskId != nil {
				taskLog.TaskID = *in.TaskId
			}
			if in.TaskName != nil {
				taskLog.TaskName = *in.TaskName
			}
			if in.TaskSlug != nil {
				taskLog.TaskSlug = *in.TaskSlug
			}
			if amount, err := strconv.ParseUint(*in.ChangeAmount, 10, 64); err == nil {
				taskLog.Integrals = uint(amount)
			}

			err = taskLog.Insert(l.ctx, tx, boil.Infer())
			if err != nil {
				return resultx.StatusError(resultx.DB_ERROR, "")
			}
		}

		if updateUserMeta {
			err = l.svcCtx.CurrentUser.IncreaseMeta(l.ctx, tx, *in.UserId, "_coupon_count", 1)
			if err != nil {
				if err != model.ErrNotFound {
					return resultx.StatusError(resultx.DB_ERROR, "")
				}
			}
		}

		if !skipIntegralLog {
			var product *mqueuex.ProductInfo
			if err := json.Unmarshal([]byte(strings.TrimSpace(*in.SourceDesc)), &product); err != nil {
				logx.Errorw("UpdateUserAssetRaw json.Unmarshal err", logx.Field("detail", err.Error()))
				return resultx.StatusError(uint32(codes.Aborted), dtmcli.ResultFailure)
			}

			pointLog := &model.UserIntegralTransactionLog{
				UserID:      *in.UserId,
				ProductID:   product.ProductId,
				ProductName: product.ProductName,
				ProductCode: product.ProductCode,
				SkuID:       product.SkuId,
				SkuCode:     product.SkuCode,
				Sku:         product.Sku,
				Status:      uint16(globalkey.StatusEnabled),
				CreatedAt:   now,
				UpdatedAt:   now,
			}
			if product.Point != nil && len(*product.Point) > 0 {
				pointLog.Points = *product.Point
			}

			err = pointLog.Insert(l.ctx, tx, boil.Infer())
			if err != nil {
				return resultx.StatusError(resultx.DB_ERROR, "")
			}
		}

		return nil
	})

	// 不再重试，走回滚
	if err == dtmcli.ErrFailure {
		return nil, resultx.StatusError(uint32(codes.Aborted), dtmcli.ResultFailure)
	}

	if err != nil {
		return nil, err
	}

	return &user.BaseResp{
		Msg: i18n.UpdateSuccess,
	}, nil
}
